﻿namespace NetFx.MSIL
{
  using System;
  using System.Text;
  using System.Collections;

  using System.Reflection;
  using System.Reflection.Emit;
  using System.Runtime.InteropServices;

  using System.Diagnostics;
  using System.Diagnostics.CodeAnalysis;
  using System.Diagnostics.SymbolStore;
  using System.Security;
  using System.Security.Permissions;

  public class EnumGenerator : TypeGenerator
  {
    #region Statics
    public static EnumGenerator of(EnumBuilder builder)
    {
      return new EnumGenerator(builder);
    }
    #endregion
    #region Properties
    public override DefType GeneratorType
    {
      get
      {
        return DefType.Enum;
      }
    }
    public virtual EnumBuilder EnumBuilder
    {
      get
      {
        return this.builder as EnumBuilder;
      }
    }
    public virtual FieldBuilder UnderlingField
    {
      get
      {
        return this.EnumBuilder.UnderlyingField;
      }
    }
    public virtual Type UnderlingType
    {
      get
      {
        return this.EnumBuilder.UnderlyingSystemType;
      }
    }
    public virtual IList Literals
    {
      get
      {
        return this.Fields;
      }
    }
    #endregion
    #region Constructors
    protected EnumGenerator(MemberInfo member) : base(member) { }
    public EnumGenerator(EnumBuilder builder):base(builder)
    {
    }
    #endregion
    #region Methods
    public override void CommitGeneration()
    {
      this.EnumBuilder.CreateType();
    }
    public virtual FieldGenerator DefineLiteral(string literalName, object literalValue)
    {
      return this.AddField(this.WrapDefineLiteral(literalName, literalValue));
    }

    protected virtual FieldBuilder WrapDefineLiteral(string literalName, object literalValue)
    {
      return this.EnumBuilder.DefineLiteral(literalName, literalValue);
    }
    #endregion

  }

  public class InnerEnumGenerator : EnumGenerator
  {
    #region Consts
    public const string UnderlingFieldName = "value__";
    #endregion
    #region Statics
    public static InnerEnumGenerator of(TypeBuilder container, string name, TypeAttributes attributes, Type underlingType)
    {
      return new InnerEnumGenerator(container, name, attributes, underlingType);
    }
    #endregion
    #region Fields
    protected Type underlingType;
    protected FieldBuilder underlingField;
    #endregion
    #region Properties
    public override EnumBuilder EnumBuilder
    {
      get { return null; }
    }
    public override FieldBuilder UnderlingField
    {
      get { return this.underlingField; }
    }
    public override Type UnderlingType
    {
      get { return this.underlingType; }
    }
    #endregion
    #region Constructors
    public InnerEnumGenerator(TypeBuilder container, string name,TypeAttributes attributes, Type underlingType):base(container)
    {
      this.builder = container.DefineNestedType(name,(TypeAttributes) ((int)attributes | 0x100), typeof(System.Enum));
      this.underlingField = this.WrapDefineField(UnderlingFieldName, underlingType, (FieldAttributes)0x201);
    }

    #endregion
    #region Methods
    public override void CommitGeneration()
    {
      this.Builder.CreateType();
    }
    protected override FieldBuilder WrapDefineLiteral(string literalName, object literalValue)
    {
      FieldBuilder field = this.WrapDefineField(literalName, this.UnderlingType, (FieldAttributes)86);
      field.SetConstant(literalValue);
      return field;
    }
    #endregion
    #region Utils
    protected override void Dispose(bool disposing)
    {
      if (disposing)
      {
        this.underlingType = null;
        this.underlingField = null;
      }
      base.Dispose(disposing);
    }
    #endregion
  }
}